/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package controller.algorithme;

import controller.AscenseurControleur;
import model.AppelAscenseur;
import model.Ascenseur;
import model.Batiment;
import model.Etage;

/**
 *
 * @author benoit
 */
public class AlgoEconomieEnergie implements Algorithme {
    private AscenseurControleur ascenseurControleur;

    public AlgoEconomieEnergie(AscenseurControleur ascenseurControleur) {
        this.ascenseurControleur = ascenseurControleur;
    }
    
    @Override
    public Ascenseur choisirAscenseur(AppelAscenseur appelAscenseur, Batiment batiment) {
        Ascenseur ascenseurChoisi=null;
        int coutAscenseurChoisi=0;
        int coutAscenseur=0;
        
        // TODO : Ne pas tester les ascenseurs en panne !!
        for(Ascenseur ascenseur : batiment.getAscenseurs().values()) {
            if( !(ascenseur.getStatut() == Ascenseur.ST_BLOQUE || ascenseur.getStatut() == Ascenseur.ST_ARRET_D_URGENCE) ) {
                if(ascenseurChoisi==null) {
                    ascenseurChoisi = ascenseur;
                    coutAscenseurChoisi = calculerCout(appelAscenseur, ascenseur);
                } else {
                    coutAscenseur = calculerCout(appelAscenseur,ascenseur);
                    if(coutAscenseur < coutAscenseurChoisi) {
                        ascenseurChoisi = ascenseur;
                        coutAscenseurChoisi = coutAscenseur;
                    }
                }
            }
        }
        
        return ascenseurChoisi;
    }
    
    private int calculerCout(AppelAscenseur appelAscenseur, Ascenseur ascenseur) {
        int cout=0;
        int sensAscenseur=0;
        int sensUtilisateur=0;
        int n = ascenseur.getNumero();
        
        /* Renseignement des sens */
        // TODO : Gérer le sensAscenseur par rapport à ses trajets et pas à son actuel de déplacement
        sensAscenseur = ascenseur.getDirectionActuel();
        if(appelAscenseur.getEtageDepart().getNumero() < appelAscenseur.getEtageArrive().getNumero()) {
            sensUtilisateur = Ascenseur.MONTEE;
        } else {
            sensUtilisateur = Ascenseur.DESCENTE;
        }
        
        /* Calcul du cout */
        if(ascenseur.getStatut() == Ascenseur.ST_EN_COURS_DE_TRAJET) {
            if(sensUtilisateur == sensAscenseur && (appelAscenseur.getEtageDepart().getNumero() - ascenseur.getEtageCourant().getNumero() >= 2)) {
                if(appelAscenseur.getEtageArrive().getNumero() <= ascenseurControleur.getEtageArriveTrajetsEnCours(n).getNumero()) {
                    cout = 0;
                } else {
                    cout += calculerCoutConsoBruteEtageDepartArrive(ascenseurControleur.getEtageArriveTrajetsEnCours(n),appelAscenseur.getEtageArrive());
                }
            } else {
                /* Coût pour finir le trajet en cours + aller chercher le nouvel */
                cout += ascenseurControleur.calculerCoutConsoTrajetsEnCours(n);
                cout += calculerCoutConsoBruteEtageDepartArrive(ascenseurControleur.getEtageArriveTrajetsEnCours(n), appelAscenseur.getEtageDepart());
            }
        /* Si l'ascenseur est en attente de déplacement */
        // TODO : Gérer le repositionnement automatique
        } else {
            /* Calcul du coût pour atteindre l'étage de départ de l'appel */
            cout += calculerCoutConsoBruteEtageDepartArrive(ascenseur.getEtageCourant(), appelAscenseur.getEtageDepart());
        }

        return cout;
    }
    
    private int calculerCoutConsoBruteEtageDepartArrive(Etage etageDepart, Etage etageArrive) {
        return Math.abs(etageDepart.getNumero() - etageArrive.getNumero()) * getConsoMonteOuDescente(etageDepart, etageArrive);
    }
    
    private int getConsoMonteOuDescente(Etage etageDepart, Etage etageArrive) {
        if(etageDepart.getNumero() < etageArrive.getNumero()) {
            return Ascenseur.CONSO_MONTEE;
        } else {
            return Ascenseur.CONSO_DESCENTE;
        }
    }
}
